


using System;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using SubSonic.DataProviders;
using SubSonic.Extensions;
using SubSonic.Linq.Structure;
using SubSonic.Query;
using SubSonic.Schema;
using System.Data.Common;
using System.Collections.Generic;

namespace GM.Model.SubSonic
{
    public partial class evolutionDB : IQuerySurface
    {

        public IDataProvider DataProvider;
        public DbQueryProvider provider;
        
        public static IDataProvider DefaultDataProvider { get; set; }

        public bool TestMode
		{
            get
			{
                return DataProvider.ConnectionString.Equals("test", StringComparison.InvariantCultureIgnoreCase);
            }
        }

        public evolutionDB() 
        {
            if (DefaultDataProvider == null) {
                DataProvider = ProviderFactory.GetProvider("EvolutionMysql");
            }
            else {
                DataProvider = DefaultDataProvider;
            }
            Init();
        }

        public evolutionDB(string connectionStringName)
        {
            DataProvider = ProviderFactory.GetProvider(connectionStringName);
            Init();
        }

		public evolutionDB(string connectionString, string providerName)
        {
            DataProvider = ProviderFactory.GetProvider(connectionString,providerName);
            Init();
        }

		public ITable FindByPrimaryKey(string pkName)
        {
            return DataProvider.Schema.Tables.SingleOrDefault(x => x.PrimaryKey.Name.Equals(pkName, StringComparison.InvariantCultureIgnoreCase));
        }

        public Query<T> GetQuery<T>()
        {
            return new Query<T>(provider);
        }
        
        public ITable FindTable(string tableName)
        {
            return DataProvider.FindTable(tableName);
        }
               
        public IDataProvider Provider
        {
            get { return DataProvider; }
            set {DataProvider=value;}
        }
        
        public DbQueryProvider QueryProvider
        {
            get { return provider; }
        }
        
        BatchQuery _batch = null;
        public void Queue<T>(IQueryable<T> qry)
        {
            if (_batch == null)
                _batch = new BatchQuery(Provider, QueryProvider);
            _batch.Queue(qry);
        }

        public void Queue(ISqlQuery qry)
        {
            if (_batch == null)
                _batch = new BatchQuery(Provider, QueryProvider);
            _batch.Queue(qry);
        }

        public void ExecuteTransaction(IList<DbCommand> commands)
		{
            if(!TestMode)
			{
                using(var connection = commands[0].Connection)
				{
                   if (connection.State == ConnectionState.Closed)
                        connection.Open();
                   
                   using (var trans = connection.BeginTransaction()) 
				   {
                        foreach (var cmd in commands) 
						{
                            cmd.Transaction = trans;
                            cmd.Connection = connection;
                            cmd.ExecuteNonQuery();
                        }
                        trans.Commit();
                    }
                    connection.Close();
                }
            }
        }

        public IDataReader ExecuteBatch()
        {
            if (_batch == null)
                throw new InvalidOperationException("There's nothing in the queue");
            if(!TestMode)
                return _batch.ExecuteReader();
            return null;
        }
			
        public Query<Adre> Adres { get; set; }
        public Query<Dzieci> Dziecis { get; set; }
        public Query<Powiadomienium> Powiadomienia { get; set; }
        public Query<Pracownik> Pracowniks { get; set; }
        public Query<Prelegenci> Prelegencis { get; set; }
        public Query<Rodzina> Rodzinas { get; set; }
        public Query<Ubezpieczenie> Ubezpieczenies { get; set; }
        public Query<Urlopy> Urlopies { get; set; }
        public Query<Wyplatum> Wyplata { get; set; }
        public Query<Zatrudnienie> Zatrudnienies { get; set; }
        public Query<ankietum> ankieta { get; set; }
        public Query<certyfikaty> certyfikaties { get; set; }
        public Query<faktury> fakturies { get; set; }
        public Query<gm_kst> gm_ksts { get; set; }
        public Query<gm_materialy> gm_materialies { get; set; }
        public Query<gm_materialy_ruchy> gm_materialy_ruchies { get; set; }
        public Query<gm_naprawy> gm_naprawies { get; set; }
        public Query<gm_srodki_trwale> gm_srodki_trwales { get; set; }
        public Query<gm_srodki_trwale_amortyzacje> gm_srodki_trwale_amortyzacjes { get; set; }
        public Query<gm_srodki_trwale_ruchy> gm_srodki_trwale_ruchies { get; set; }
        public Query<kontum> konta { get; set; }
        public Query<ksiega> ksiegas { get; set; }
        public Query<marketing_projekty> marketing_projekties { get; set; }
        public Query<s_prelegent> s_prelegents { get; set; }
        public Query<s_sala> s_salas { get; set; }
        public Query<s_sprzet> s_sprzets { get; set; }
        public Query<sale> sales { get; set; }
        public Query<szkolenium> szkolenia { get; set; }
        public Query<szkolenie_uczestnicy> szkolenie_uczestnicies { get; set; }
        public Query<uczestnicy> uczestnicies { get; set; }
        public Query<user> users { get; set; }

			

        #region ' Aggregates and SubSonic Queries '
        public Select SelectColumns(params string[] columns)
        {
            return new Select(DataProvider, columns);
        }

        public Select Select
        {
            get { return new Select(this.Provider); }
        }

        public Insert Insert
		{
            get { return new Insert(this.Provider); }
        }

        public Update<T> Update<T>() where T:new()
		{
            return new Update<T>(this.Provider);
        }

        public SqlQuery Delete<T>(Expression<Func<T,bool>> column) where T:new()
        {
            LambdaExpression lamda = column;
            SqlQuery result = new Delete<T>(this.Provider);
            result = result.From<T>();
            result.Constraints=lamda.ParseConstraints().ToList();
            return result;
        }

        public SqlQuery Max<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = DataProvider.FindTable(objectName).Name;
            return new Select(DataProvider, new Aggregate(colName, AggregateFunction.Max)).From(tableName);
        }

        public SqlQuery Min<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Min)).From(tableName);
        }

        public SqlQuery Sum<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Sum)).From(tableName);
        }

        public SqlQuery Avg<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Avg)).From(tableName);
        }

        public SqlQuery Count<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Count)).From(tableName);
        }

        public SqlQuery Variance<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.Var)).From(tableName);
        }

        public SqlQuery StandardDeviation<T>(Expression<Func<T,object>> column)
        {
            LambdaExpression lamda = column;
            string colName = lamda.ParseObjectValue();
            string objectName = typeof(T).Name;
            string tableName = this.Provider.FindTable(objectName).Name;
            return new Select(this.Provider, new Aggregate(colName, AggregateFunction.StDev)).From(tableName);
        }

        #endregion

        void Init()
        {
            provider = new DbQueryProvider(this.Provider);

            #region ' Query Defs '
            Adres = new Query<Adre>(provider);
            Dziecis = new Query<Dzieci>(provider);
            Powiadomienia = new Query<Powiadomienium>(provider);
            Pracowniks = new Query<Pracownik>(provider);
            Prelegencis = new Query<Prelegenci>(provider);
            Rodzinas = new Query<Rodzina>(provider);
            Ubezpieczenies = new Query<Ubezpieczenie>(provider);
            Urlopies = new Query<Urlopy>(provider);
            Wyplata = new Query<Wyplatum>(provider);
            Zatrudnienies = new Query<Zatrudnienie>(provider);
            ankieta = new Query<ankietum>(provider);
            certyfikaties = new Query<certyfikaty>(provider);
            fakturies = new Query<faktury>(provider);
            gm_ksts = new Query<gm_kst>(provider);
            gm_materialies = new Query<gm_materialy>(provider);
            gm_materialy_ruchies = new Query<gm_materialy_ruchy>(provider);
            gm_naprawies = new Query<gm_naprawy>(provider);
            gm_srodki_trwales = new Query<gm_srodki_trwale>(provider);
            gm_srodki_trwale_amortyzacjes = new Query<gm_srodki_trwale_amortyzacje>(provider);
            gm_srodki_trwale_ruchies = new Query<gm_srodki_trwale_ruchy>(provider);
            konta = new Query<kontum>(provider);
            ksiegas = new Query<ksiega>(provider);
            marketing_projekties = new Query<marketing_projekty>(provider);
            s_prelegents = new Query<s_prelegent>(provider);
            s_salas = new Query<s_sala>(provider);
            s_sprzets = new Query<s_sprzet>(provider);
            sales = new Query<sale>(provider);
            szkolenia = new Query<szkolenium>(provider);
            szkolenie_uczestnicies = new Query<szkolenie_uczestnicy>(provider);
            uczestnicies = new Query<uczestnicy>(provider);
            users = new Query<user>(provider);
            #endregion


            #region ' Schemas '
        	if(DataProvider.Schema.Tables.Count == 0)
			{
            	DataProvider.Schema.Tables.Add(new AdresTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new DzieciTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new PowiadomieniaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new PracownikTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new PrelegenciTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new RodzinaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new UbezpieczenieTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new UrlopyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new WyplataTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ZatrudnienieTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ankietaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new certyfikatyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new fakturyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_kstTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_materialyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_materialy_ruchyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_naprawyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_srodki_trwaleTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_srodki_trwale_amortyzacjeTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new gm_srodki_trwale_ruchyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new kontaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new ksiegaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new marketing_projektyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new s_prelegentTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new s_salaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new s_sprzetTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new saleTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new szkoleniaTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new szkolenie_uczestnicyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new uczestnicyTable(DataProvider));
            	DataProvider.Schema.Tables.Add(new usersTable(DataProvider));
            }
            #endregion
        }
        

        #region ' Helpers '
            
        internal static DateTime DateTimeNowTruncatedDownToSecond() {
            var now = DateTime.Now;
            return now.AddTicks(-now.Ticks % TimeSpan.TicksPerSecond);
        }

        #endregion

    }
}